package com.duobaoyu.dby.supply.admin.service.impl;

import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.duobaoyu.dby.channel.adapter.enums.ChannelCodeEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.product.GoodsStatusEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.refund.AfterSaleStatusEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.refund.AfterSaleTypeEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.refund.PickupProductEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.refund.RefundStatusEnum;
import com.duobaoyu.dby.channel.adapter.util.ChannelCodeUtils;
import com.duobaoyu.dby.channel.boundary.bean.refund.result.AfterSaleAttributesResult;
import com.duobaoyu.dby.channel.common.util.SupplyCollectionUtils;
import com.duobaoyu.dby.common.mybatis.support.ParamConvert;
import com.duobaoyu.dby.common.mybatis.util.EnumUtils;
import com.duobaoyu.dby.supply.admin.converter.AdminAfterSaleBizServiceConverter;
import com.duobaoyu.dby.supply.admin.converter.SupplyChainAdminConverter;
import com.duobaoyu.dby.supply.admin.service.AdminAfterSaleBizService;
import com.duobaoyu.dby.supply.biz.client.boundary.order.bean.bo.OrderBO;
import com.duobaoyu.dby.supply.biz.client.boundary.order.bean.bo.OrderProductBO;
import com.duobaoyu.dby.supply.biz.client.boundary.order.bean.bo.OrderQueryInBO;
import com.duobaoyu.dby.supply.biz.client.boundary.refund.AfterSaleBoundaryClientImpl;
import com.duobaoyu.dby.supply.biz.client.resource.ResourceBusinessConfigAdminClient;
import com.duobaoyu.dby.supply.biz.client.resource.ResourceTaskAsyncAdminClient;
import com.duobaoyu.dby.supply.biz.constant.OperateSourceConstants;
import com.duobaoyu.dby.supply.biz.enums.AfterSaleSourceEnum;
import com.duobaoyu.dby.supply.biz.enums.OrderParentTypeEnum;
import com.duobaoyu.dby.supply.biz.service.config.PreWarningConfigService;
import com.duobaoyu.dby.supply.biz.service.order.OrderService;
import com.duobaoyu.dby.supply.biz.service.refund.AfterSaleService;
import com.duobaoyu.dby.supply.biz.service.refund.AfterSaleStateMachine;
import com.duobaoyu.dby.supply.biz.service.refund.event.AfterSaleStateChangeEvent;
import com.duobaoyu.dby.supply.common.biz.bo.refund.*;
import com.duobaoyu.dby.supply.common.biz.dto.config.PreWarningConditionDTO;
import com.duobaoyu.dby.supply.common.biz.dto.refund.*;
import com.duobaoyu.dby.supply.common.biz.enums.AuditAgreeTypeEnum;
import com.duobaoyu.dby.supply.common.biz.enums.ButtonTypeEnum;
import com.duobaoyu.dby.supply.common.biz.vo.refund.*;
import com.duobaoyu.dby.supply.core.common.exception.CustomAssert;
import com.duobaoyu.dby.supply.core.task.bean.exporttask.ExportParam;
import com.duobaoyu.dby.supply.core.task.enums.BizTaskTypeEnum;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by shuming on 2023/10/9 10:06
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class AdminAfterSaleBizServiceImpl implements AdminAfterSaleBizService {

    private final AfterSaleService afterSaleService;
    private final PreWarningConfigService preWarningConfigService;
    private final ResourceTaskAsyncAdminClient resourceTaskAsyncAdminClient;
    private final AfterSaleStateMachine afterSaleStateMachine;
    private final SupplyChainAdminConverter converter;
    private final AfterSaleBoundaryClientImpl afterSaleBoundaryClient;
    private final OrderService orderService;
    private final ResourceBusinessConfigAdminClient resourceBusinessConfigAdminClient;
    private final AdminAfterSaleBizServiceConverter adminAfterSaleBizServiceConverter;

    @Override
    public Page<AfterSaleListVO> queryPage(AfterSaleApplyQueryDTO afterSaleApplyQuery) {
        //添加预警策略查询条件
        if (ObjectUtils.isNotEmpty(afterSaleApplyQuery.getPreWarningStrategyId())) {
            PreWarningConditionDTO preWarningCondition = preWarningConfigService.getPreWarningCondition(afterSaleApplyQuery.getPreWarningStrategyId());
            if (Objects.nonNull(preWarningCondition)) {
                afterSaleApplyQuery.setPreWarningCondition(preWarningCondition);
            }
        }

        Page<AfterSaleListVO> afterSaleApplyPage = afterSaleService.queryPage(ParamConvert.getPage(afterSaleApplyQuery), afterSaleApplyQuery);
        for (AfterSaleListVO afterSaleApply : afterSaleApplyPage.getRecords()) {
            if (StringUtils.isNotBlank(afterSaleApply.getShowServerName())) {
                afterSaleApply.setShowServerName(resourceBusinessConfigAdminClient.getBizCode(afterSaleApply.getShowServerName()).getBizDescribe());
            } else if (StringUtils.isNotBlank(afterSaleApply.getServerName())) {
                afterSaleApply.setShowServerName(resourceBusinessConfigAdminClient.getBizCode(afterSaleApply.getServerName()).getBizDescribe());
            }
            afterSaleApply.setChannelCodeDesc(ChannelCodeEnum.getChannelCodeEnumByCode(afterSaleApply.getChannelCode()).getDescribe());
            AfterSaleStatusEnum afterSaleStatusEnum = AfterSaleStatusEnum.getAfterSaleStatusEnum(afterSaleApply.getStatus());
            if (Objects.nonNull(afterSaleStatusEnum)) {
                afterSaleApply.setStatusDesc(afterSaleStatusEnum.getDescribe());
            }

            if (Objects.nonNull(afterSaleApply.getAfterSaleType())) {
                AfterSaleTypeEnum afterSaleTypeEnum = AfterSaleTypeEnum.getAfterSaleTypeEnum(afterSaleApply.getAfterSaleType());
                if (Objects.nonNull(afterSaleTypeEnum)) {
                    afterSaleApply.setAfterSaleTypeDesc(afterSaleTypeEnum.getDescribe());
                }
            }

            AfterSaleButtonVO afterSaleButtonVO = checkAfterSaleStatus(afterSaleApply.getStatus(),
                    afterSaleApply.getChannelCode(), afterSaleApply.getAfterSaleType(), afterSaleApply.getAfterSaleSource());
            afterSaleApply.setButtonType(afterSaleButtonVO.getButtonType());
            afterSaleApply.setAgreeType(afterSaleButtonVO.getAgreeType());
            afterSaleApply.setShowDealButton(needDeal(afterSaleApply, afterSaleButtonVO));
        }
        return afterSaleApplyPage;
    }

    private AfterSaleButtonVO checkAfterSaleStatus(Integer status, String channelCode, Integer afterSaleType, Integer afterSaleSource) {
        AfterSaleButtonVO afterSaleButton = new AfterSaleButtonVO();
        Boolean hasAfterSaleInterface = channelHasAfterSaleInterface(channelCode);

        AfterSaleStatusEnum afterSaleStatus = AfterSaleStatusEnum.getAfterSaleStatusEnum(status);
        switch (afterSaleStatus) {
            //待平台审核
            case WAIT_DBY_AUDIT:
                afterSaleButton.setButtonType(Lists.newArrayList(ButtonTypeEnum.AUDIT.getValue()));
                if (hasAfterSaleInterface) {
                    afterSaleButton.setAgreeType(AuditAgreeTypeEnum.PLATFORM_AUDIT_TO_CHANNEL.getValue());
                } else {
                    if (EnumUtils.eq(AfterSaleTypeEnum.REFUND, afterSaleType)) {
                        afterSaleButton.setAgreeType(AuditAgreeTypeEnum.PLATFORM_AMOUNT_REFUND.getValue());
                    } else {
                        afterSaleButton.setAgreeType(AuditAgreeTypeEnum.ADDRESS_FILL.getValue());
                    }
                    if (EnumUtils.eq(AfterSaleSourceEnum.SYSTEM, afterSaleSource)) {
                        afterSaleButton.setAgreeType(AuditAgreeTypeEnum.PLATFORM_CONFIRM.getValue());
                    }
                }
                return afterSaleButton;
            // 待驳回确认
            case WAIT_REJECT_CONFIRM:
                afterSaleButton.setButtonType(Lists.newArrayList(ButtonTypeEnum.REJECT_CONFIRM.getValue(),
                        ButtonTypeEnum.RECOMMIT.getValue()));
                return afterSaleButton;
            // 地址回填
            case CHANNEL_AUDIT_SUCCESS:
                if (notAfterSaleChannelReturnAddress(channelCode)) {
                    afterSaleButton.setButtonType(Lists.newArrayList(ButtonTypeEnum.ADDRESS_FILL.getValue()));
                }
                return afterSaleButton;
            // 退款处理
            case PENDING_RECEIPT:
                if (!hasAfterSaleInterface) {
                    afterSaleButton.setButtonType(Lists.newArrayList(ButtonTypeEnum.REFUND.getValue()));
                    afterSaleButton.setAgreeType(AuditAgreeTypeEnum.PLATFORM_AMOUNT_REFUND.getValue());
                }
                return afterSaleButton;
            default:
                return afterSaleButton;
        }
    }

    /**
     * 渠道是否有售后对接接口
     *
     * @param afterSaleChannel
     * @return
     */
    private Boolean channelHasAfterSaleInterface(String afterSaleChannel) {
        Set<ChannelCodeEnum> noAfterSaleApiChannel = ChannelCodeUtils.channelNoAfterSaleInterface();
        return !noAfterSaleApiChannel.contains(ChannelCodeEnum.getChannelCodeEnumByCode(afterSaleChannel));
    }

    private Boolean notAfterSaleChannelReturnAddress(String afterSaleChannel) {
        return ChannelCodeUtils.notAfterSaleChannelReturnAddress()
                .contains(ChannelCodeEnum.getChannelCodeEnumByCode(afterSaleChannel));
    }

    private Boolean needDeal(AfterSaleListVO afterSaleList, AfterSaleButtonVO afterSaleButton) {
        if (Objects.isNull(afterSaleButton.getButtonType())
                && Objects.isNull(afterSaleButton.getAgreeType())) {
            return Boolean.FALSE;
        }
        List<Integer> stateList = AfterSaleStatusEnum.needDealValueList();
        stateList.remove(AfterSaleStatusEnum.WAIT_REJECT_CONFIRM.getValue());
        if (stateList.contains(afterSaleList.getStatus())) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    @Override
    public AfterSaleVO afterSaleDetail(String afterSaleSn) {
        AfterSaleQuery afterSale = new AfterSaleQuery();
        afterSale.setAfterSaleSn(afterSaleSn);
        AfterSaleOutBO afterSaleOut = afterSaleService.queryAfterSale(afterSale);

        AfterSaleItemOutBO item = SupplyCollectionUtils.getSingleDataFirst(afterSaleOut.getItems(), AfterSaleItemOutBO::new);
        AfterSaleVO afterSaleView = this.buildAfterSale(afterSaleOut, item);
        List<AfterSaleItemVO> afterSaleItemList = converter.toAfterSaleItemList(afterSaleOut.getItems());
        afterSaleView.setAfterSaleItemList(afterSaleItemList);

        AfterSaleBaseInfoVO afterSaleBaseInfo = this.convertAfterSaleBaseInfo(afterSaleOut, item);
        afterSaleView.setAfterSaleBaseInfo(afterSaleBaseInfo);

        // 多商品时仅待支付整单取消,以第一条基础数据查询扩展信息
        AfterSalePickUpBO afterSalePickUp = afterSaleService.queryPickUp(afterSaleOut.getAfterSaleSn());
        if (Objects.nonNull(afterSalePickUp)) {
            afterSaleBaseInfo.setPickupType(afterSalePickUp.getPickupType());
            afterSaleBaseInfo.setPickupTypeDesc(
                    PickupProductEnum.getPickupWareEnum(afterSalePickUp.getPickupType()).getDescribe());
            afterSaleBaseInfo.setPickupAddress(afterSalePickUp.getPickupAddress());
            afterSaleBaseInfo.setReservationStartTime(afterSalePickUp.getReservationStartTime());
            afterSaleBaseInfo.setReservationEndTime(afterSalePickUp.getReservationEndTime());
        }

        List<AfterSaleWayBillOutBO> wayBillOutList = afterSaleService.queryAfterSaleWaybills(afterSaleOut.getAfterSaleSn());
        if (CollectionUtils.isNotEmpty(wayBillOutList)) {
            AfterSaleWayBillOutBO afterSaleWayBillOut = SupplyCollectionUtils.getSingleDataFirst(wayBillOutList, AfterSaleWayBillOutBO::new);
            afterSaleBaseInfo.setExpressCompany(afterSaleWayBillOut.getExpressCompany());
            afterSaleBaseInfo.setExpressCode(afterSaleWayBillOut.getExpressCode());
        }

        AfterSaleButtonVO afterSaleButton = checkAfterSaleStatus(afterSaleView.getAfterSalesStatus(),
                afterSaleView.getChannelCode(), afterSaleView.getAfterSaleType(), afterSaleView.getAfterSaleSource());
        afterSaleView.setButtonType(afterSaleButton.getButtonType());
        afterSaleView.setAgreeType(afterSaleButton.getAgreeType());
        return afterSaleView;
    }

    private AfterSaleBaseInfoVO convertAfterSaleBaseInfo(AfterSaleOutBO afterSaleOut, AfterSaleItemOutBO afterSaleItemOut) {
        AfterSaleBaseInfoVO afterSaleBaseInfo = new AfterSaleBaseInfoVO();
        AfterSaleContactInfoBO contactInfo = afterSaleOut.getContactInfo();
        afterSaleBaseInfo.setCustomerContactName(contactInfo.getCustomerContactName());
        afterSaleBaseInfo.setCustomerEmail(contactInfo.getCustomerEmail());
        afterSaleBaseInfo.setCustomerMobilePhone(contactInfo.getCustomerMobilePhone());
        afterSaleBaseInfo.setCustomerPostcode(contactInfo.getCustomerPostcode());

        afterSaleBaseInfo.setOrderSn(afterSaleOut.getOrderSn());
        afterSaleBaseInfo.setGoodsStatus(afterSaleItemOut.getGoodsStatus());
        afterSaleBaseInfo.setGoodsStatusDesc(GoodsStatusEnum.getGoodsStatusDescribe(afterSaleItemOut.getGoodsStatus()));
        afterSaleBaseInfo.setAfterSaleReturnAmount(afterSaleOut.getChannelActualRefundAmount());
        afterSaleBaseInfo.setApplyAfterSaleAmount(afterSaleOut.getApplyRefundAmount());
        afterSaleBaseInfo.setFreightApplyRefundAmount(afterSaleOut.getFreightApplyRefundAmount());
        afterSaleBaseInfo.setChannelFreightActualRefundAmount(afterSaleOut.getChannelFreightActualRefundAmount());
        afterSaleBaseInfo.setCreateTime(afterSaleOut.getCreateTime());
        return afterSaleBaseInfo;
    }

    private AfterSaleVO buildAfterSale(AfterSaleOutBO afterSaleOut, AfterSaleItemOutBO afterSaleItemOut) {
        AfterSaleVO afterSale = new AfterSaleVO();
        afterSale.setAfterSaleSn(afterSaleOut.getAfterSaleSn());
        afterSale.setAfterSalesStatus(afterSaleOut.getStatus());
        afterSale.setAfterSaleSource(afterSaleOut.getAfterSaleSource());
        afterSale.setAfterSaleImage(afterSaleItemOut.getAfterSaleImageList());
        afterSale.setAfterSaleRemark(afterSaleItemOut.getAfterSaleRemark());
        afterSale.setAfterSalesStatusDesc(AfterSaleStatusEnum.getAfterSaleStatusDescribe(afterSaleOut.getStatus()));
        afterSale.setReasonCode(afterSaleItemOut.getReasonCode());
        afterSale.setReasonName(afterSaleItemOut.getReasonName());
        afterSale.setFailReason(afterSaleOut.getFailReason());
        afterSale.setChannelCode(afterSaleOut.getChannelCode());
        afterSale.setAfterSaleType(afterSaleOut.getAfterSaleType());
        afterSale.setAfterSaleTypeDesc(AfterSaleTypeEnum.getAfterSaleTypeEnum(afterSaleOut.getAfterSaleType()).getDescribe());
        if (StringUtils.isNotBlank(afterSaleOut.getShowServerName())) {
            afterSale.setShowServerName(resourceBusinessConfigAdminClient.getBizCode(afterSaleOut.getShowServerName()).getBizDescribe());
        } else if (StringUtils.isNotBlank(afterSaleOut.getServerName())) {
            afterSale.setShowServerName(resourceBusinessConfigAdminClient.getBizCode(afterSaleOut.getServerName()).getBizDescribe());
        }
        afterSale.setSendBackAddress(converter.toAfterSaleSendBackAddressVO(afterSaleOut.getCustomerReturnAddress()));
        return afterSale;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean agreeAfterSale(AfterSaleChannelAddressDTO afterSaleChannelAddress) {
        AfterSaleQuery afterSaleQuery = new AfterSaleQuery();
        afterSaleQuery.setAfterSaleSn(afterSaleChannelAddress.getAfterSaleSn());
        AfterSaleOutBO afterSaleOut = afterSaleService.queryAfterSale(afterSaleQuery);
        CustomAssert.notNull(afterSaleOut, "售后申请信息不存在");
        if (EnumUtils.eq(AfterSaleStatusEnum.TO_BE_SUBMITTED_FOR_CHANNEL, afterSaleOut.getStatus())) {
            log.info("售后申请单已是待提交渠道审核，申请afterSaleSn = {}", afterSaleChannelAddress.getAfterSaleSn());
            return true;
        }

        AfterSaleStateContext afterSaleStateContext = new AfterSaleStateContext();
        afterSaleStateContext.setAfterSale(afterSaleOut);
        afterSaleStateContext.setOperateSource(OperateSourceConstants.BACKSTAGE);

        if (channelHasAfterSaleInterface(afterSaleOut.getChannelCode())) {
            afterSaleStateContext.setCurrentAfterSaleStatus(AfterSaleStatusEnum.TO_BE_SUBMITTED_FOR_CHANNEL.getValue());
            afterSaleStateContext.setChangeContentOperate(AfterSaleStateContext.ChangeContentOperate.builder().build());
        } else {
            afterSaleStateContext.setCurrentAfterSaleStatus(AfterSaleStatusEnum.TO_BE_SENT_BACK_BY_BUYER.getValue());
            CustomAssert.notNull(afterSaleChannelAddress.getChannelReturnName(), "渠道返件联系方式不可为空");
            CustomAssert.notNull(afterSaleChannelAddress.getChannelReturnAddress(), "渠道返件地址不可为空");
            CustomAssert.notNull(afterSaleChannelAddress.getChannelReturnTel(), "渠道返件联系方式不可为空");
            CustomerReturnAddressBO customerReturnAddress = new CustomerReturnAddressBO();
            customerReturnAddress.setChannelAfterServiceReceiver(afterSaleChannelAddress.getChannelReturnName());
            customerReturnAddress.setChannelAfterServiceAddress(afterSaleChannelAddress.getChannelReturnAddress());
            customerReturnAddress.setChannelAfterServicePhone(afterSaleChannelAddress.getChannelReturnTel());
            afterSaleStateContext.setChangeContentOperate(AfterSaleStateContext.ChangeContentOperate.builder()
                    .customerReturnAddress(customerReturnAddress).build());
        }
        return afterSaleStateMachine.exe(afterSaleStateContext);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean rejectAfterSale(String afterSaleSn, String rejectReason) {
        AfterSaleQuery afterSaleQuery = new AfterSaleQuery();
        afterSaleQuery.setAfterSaleSn(afterSaleSn);
        AfterSaleOutBO afterSaleOut = afterSaleService.queryAfterSale(afterSaleQuery);
        CustomAssert.notNull(afterSaleOut, "售后申请信息不存在");

        if (EnumUtils.eq(AfterSaleStatusEnum.FAIL, afterSaleOut.getStatus())) {
            log.info("售后申请单已是审核成功，申请afterSaleSn = {}", afterSaleSn);
            return true;
        }
        AfterSaleStateContext afterSaleStateContext = new AfterSaleStateContext();
        afterSaleStateContext.setAfterSale(afterSaleOut);
        if (StringUtils.isNotBlank(rejectReason)) {
            afterSaleStateContext.setChangeContentOperate(AfterSaleStateContext.ChangeContentOperate.builder()
                    .failReason(rejectReason).build());
        }
        afterSaleStateContext.setOperateSource(OperateSourceConstants.BACKSTAGE);
        afterSaleStateContext.setCurrentAfterSaleStatus(AfterSaleStatusEnum.FAIL.getValue());
        return afterSaleStateMachine.exe(afterSaleStateContext);
    }

    @Override
    public Boolean modifyAfterSale(AfterSaleUpdateDTO afterSaleUpdate) {
        AfterSaleQuery afterSaleQuery = new AfterSaleQuery();
        afterSaleQuery.setAfterSaleSn(afterSaleUpdate.getAfterSaleSn());
        AfterSaleOutBO afterSaleOut = afterSaleService.queryAfterSale(afterSaleQuery);
        CustomAssert.notNull(afterSaleOut, "售后申请信息不存在");
        CustomAssert.isTrue(EnumUtils.eq(AfterSaleStatusEnum.WAIT_REJECT_CONFIRM, afterSaleOut.getStatus()), "非待驳回确认状态，不可修改相关信息");

        AfterSaleStateContext afterSaleStateContext = new AfterSaleStateContext();
        afterSaleStateContext.setAfterSale(afterSaleOut);
        afterSaleStateContext.setOperateSource(OperateSourceConstants.BACKSTAGE);
        afterSaleStateContext.setChangeContentOperate(convertUpdateContext(afterSaleOut, afterSaleUpdate));
        afterSaleStateContext.setCurrentAfterSaleStatus(AfterSaleStatusEnum.TO_BE_SUBMITTED_FOR_CHANNEL.getValue());
        return afterSaleStateMachine.exe(afterSaleStateContext);
    }

    private AfterSaleStateContext.ChangeContentOperate convertUpdateContext(AfterSaleOutBO afterSaleOut,
                                                                            AfterSaleUpdateDTO afterSaleUpdate) {
        List<AfterSaleItemUpdateDTO> afterSaleItemList = afterSaleUpdate.getAfterSaleItemList();
        Map<Long, AfterSaleItemUpdateDTO> updateItemMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(afterSaleItemList)) {
            updateItemMap = afterSaleItemList.stream()
                    .collect(Collectors.toMap(AfterSaleItemUpdateDTO::getItemId, Function.identity(), (k1, k2) -> k1));
        }

        AfterSaleStateContext.ChangeContentOperate changeContent = new AfterSaleStateContext.ChangeContentOperate();
        BigDecimal freightApplyRefundAmount = afterSaleUpdate.getFreightApplyRefundAmount();
        changeContent.setFreightApplyRefundAmount(freightApplyRefundAmount);

        List<AfterSaleStateContext.AfterSaleUpdateItemInfo> afterSaleItemInfoList = Lists.newArrayList();
        List<AfterSaleItemOutBO> items = afterSaleOut.getItems();
        for (AfterSaleItemOutBO item : items) {
            AfterSaleStateContext.AfterSaleUpdateItemInfo afterSaleUpdateItemInfo =
                    new AfterSaleStateContext.AfterSaleUpdateItemInfo();
            if (StringUtils.isNotBlank(afterSaleUpdate.getReasonCode())
                    && StringUtils.isNotBlank(afterSaleUpdate.getReasonName())) {
                afterSaleUpdateItemInfo.setReasonCode(afterSaleUpdate.getReasonCode());
                afterSaleUpdateItemInfo.setReasonName(afterSaleUpdate.getReasonName());
            }
            if (Objects.nonNull(afterSaleUpdate.getGoodsStatus())) {
                afterSaleUpdateItemInfo.setGoodsStatus(afterSaleUpdate.getGoodsStatus());
            }
            afterSaleUpdateItemInfo.setId(item.getId());
            afterSaleUpdateItemInfo.setFreightApplyRefundAmount(freightApplyRefundAmount);
            if (Objects.nonNull(freightApplyRefundAmount)) {
                freightApplyRefundAmount = freightApplyRefundAmount.subtract(freightApplyRefundAmount);
            }
            AfterSaleItemUpdateDTO afterSaleItemUpdate = updateItemMap.get(item.getId());
            if (Objects.nonNull(afterSaleItemUpdate)) {
				BigDecimal applyAfterSalesAmount = afterSaleItemUpdate.getChannelApplyAfterSalesAmount();
				CustomAssert.isTrue(item.getChannelActualPaidAmount().compareTo(applyAfterSalesAmount) >= 0,
						"修改金额不得大于该商品实际支付金额");
                afterSaleUpdateItemInfo.setChannelApplyAfterSaleAmount(applyAfterSalesAmount);
            }
            afterSaleItemInfoList.add(afterSaleUpdateItemInfo);
        }
        changeContent.setAfterSaleItemInfoList(afterSaleItemInfoList);
        return changeContent;
    }

    @Override
    public Boolean agreeRefund(String afterSaleSn, BigDecimal refundAmount, BigDecimal refundFreightAmount) {
        AfterSaleQuery afterSaleQuery = new AfterSaleQuery();
        afterSaleQuery.setAfterSaleSn(afterSaleSn);
        AfterSaleOutBO afterSaleOut = afterSaleService.queryAfterSale(afterSaleQuery);
        CustomAssert.notNull(afterSaleOut, "售后申请信息不存在");
        BigDecimal applyRefundAmount = afterSaleOut.getApplyRefundAmount();
        BigDecimal freightApplyRefundAmount = afterSaleOut.getFreightApplyRefundAmount();
        CustomAssert.isTrue(refundAmount.compareTo(applyRefundAmount) <= 0, "实际退款金额需小于申请退款金额");
        CustomAssert.isTrue(refundFreightAmount.compareTo(freightApplyRefundAmount) <= 0, "实际退款运费需小于申请退款运费");
        CustomAssert.isTrue(EnumUtils.eq(AfterSaleSourceEnum.USER, afterSaleOut.getAfterSaleSource()), "非用户申请来源，不可发起退款");

        boolean canRefund = false;
        if (!channelHasAfterSaleInterface(afterSaleOut.getChannelCode())) {
            canRefund = (EnumUtils.eq(AfterSaleTypeEnum.REFUND, afterSaleOut.getAfterSaleType())
                    && EnumUtils.eq(AfterSaleStatusEnum.WAIT_DBY_AUDIT, afterSaleOut.getStatus()))
                    || EnumUtils.eq(AfterSaleStatusEnum.PENDING_RECEIPT, afterSaleOut.getStatus());
        }
        CustomAssert.isTrue(canRefund, "当前售后单状态不可退款");

        AfterSaleStateContext afterSaleStateContext = new AfterSaleStateContext();
        afterSaleStateContext.setAfterSale(afterSaleOut);
        afterSaleStateContext.setOperateSource(OperateSourceConstants.BACKSTAGE);

        List<AfterSaleItemOutBO> items = afterSaleOut.getItems();
        List<AfterSaleStateContext.AfterSaleUpdateItemInfo> updateItems = new ArrayList<>();
        for (AfterSaleItemOutBO item : items) {
            AfterSaleStateContext.AfterSaleUpdateItemInfo afterSaleUpdateItemInfo
                    = new AfterSaleStateContext.AfterSaleUpdateItemInfo();
            afterSaleUpdateItemInfo.setId(item.getId());
            afterSaleUpdateItemInfo.setChannelActualRefundAmount(refundAmount);
            afterSaleUpdateItemInfo.setChannelFreightActualRefundAmount(refundFreightAmount);
            updateItems.add(afterSaleUpdateItemInfo);
        }
        afterSaleStateContext.setChangeContentOperate(AfterSaleStateContext.ChangeContentOperate.builder()
                .channelActualRefundAmount(refundAmount)
                .channelFreightActualRefundAmount(refundFreightAmount)
                .afterSaleItemInfoList(updateItems)
                .build());
        afterSaleStateContext.setCurrentAfterSaleStatus(AfterSaleStatusEnum.TO_BE_CONFIRMED_BY_USER.getValue());
        return afterSaleStateMachine.exe(afterSaleStateContext);
    }

    @Override
    public Boolean afterSaleExport(AfterSaleApplyQueryDTO afterSaleApplyQuery) {
        resourceTaskAsyncAdminClient.asyncExport(ExportParam.<String>builder()
                .exportDataType(BizTaskTypeEnum.SUPPLY_CHAIN_PURCHASE_AFTER_SALE_ORDER.getValue())
                .searchParameter(JSON.toJSONString(afterSaleApplyQuery, SerializerFeature.WriteMapNullValue))
                .exportedFieldsParameter(Collections.emptyList())
                .build());
        return Boolean.TRUE;
    }

    @Override
    public List<ReasonVO> queryAfterSaleAttributes(String afterSaleSn) {
        AfterSaleQuery afterSaleQuery = new AfterSaleQuery();
        afterSaleQuery.setAfterSaleSn(afterSaleSn);
        AfterSaleOutBO afterSaleOut = afterSaleService.queryAfterSale(afterSaleQuery);
        CustomAssert.notNull(afterSaleOut, "售后申请信息不存在");
        if (EnumUtils.eq(AfterSaleStatusEnum.COMPLETED, afterSaleOut.getStatus())
                || EnumUtils.eq(AfterSaleStatusEnum.TO_BE_CONFIRMED_BY_USER, afterSaleOut.getStatus())) {
            return Collections.emptyList();
        }
        OrderQueryInBO query = new OrderQueryInBO();
        query.setOrderSnList(Lists.newArrayList(afterSaleOut.getOrderSn()));
        query.setParentType(OrderParentTypeEnum.AFTER_SPLIT.getValue());
        query.setReturnProduct(true);
        List<OrderBO> orders = orderService.list(query);
        CustomAssert.notEmpty(orders, "售后申请订单信息异常");
        OrderBO order = SupplyCollectionUtils.getSingleDataFirst(orders, OrderBO::new);
        List<AfterSaleAttributesResult> afterSaleAttributesResultList
                = getSaleAttributesResultList(afterSaleOut, orders, order);
        if (CollectionUtils.isEmpty(afterSaleAttributesResultList)) {
            return Lists.newArrayList();
        }

        List<AfterSaleAttributesResult.ReasonDetail> reasonDetails =
                filterAfterSaleTypeReason(afterSaleOut.getAfterSaleType(), afterSaleAttributesResultList);

        List<ReasonVO> reasons = Lists.newArrayList();
        for (AfterSaleAttributesResult.ReasonDetail reasonDetail : reasonDetails) {
            ReasonVO reason = new ReasonVO();
            reason.setReasonCode(reasonDetail.getChannelAfterSaleReasonCode());
            reason.setReasonName(reasonDetail.getChannelAfterSaleReason());
            reasons.add(reason);
        }
        return reasons;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean fixData(AfterSaleFixDTO afterSaleFix) {
        AfterSaleQuery afterSaleQuery = new AfterSaleQuery();
        AfterSaleFixDTO.Content content = afterSaleFix.getContent();
        afterSaleQuery.setAfterSaleSn(content.getAfterSaleSn());
        AfterSaleOutBO afterSaleOut = afterSaleService.queryAfterSale(afterSaleQuery);
        CustomAssert.notNull(afterSaleOut, "售后数据不存在");
        List<AfterSaleFixDTO.Item> items = content.getItems();
        if (CollectionUtils.isNotEmpty(items)) {
            Set<Long> inputItemIds = items.stream().map(AfterSaleFixDTO.Item::getId).collect(Collectors.toSet());
            Set<Long> existItemIds = afterSaleOut.getItems().stream().map(AfterSaleItemOutBO::getId).collect(Collectors.toSet());
            CustomAssert.isTrue(Objects.equals(existItemIds,inputItemIds), "明细数据不完整");
        }
        List<AfterSaleItemInBO> existAfterSaleItems = adminAfterSaleBizServiceConverter.convertAfterSaleItemIn(afterSaleOut.getItems());
        adminAfterSaleBizServiceConverter.copyAfterSaleItem(existAfterSaleItems, content.getItems());

        AfterSaleModifyInBO modify = adminAfterSaleBizServiceConverter.convertAfterSaleModifyIn(content);
        modify.setId(afterSaleOut.getId());
        modify.setAfterSaleSn(afterSaleOut.getAfterSaleSn());
        modify.setAfterSaleItems(existAfterSaleItems);
        List<AfterSaleItemInBO> afterSaleItems = modify.getAfterSaleItems();
        afterSaleItems.forEach(e -> {
            e.setAfterSaleType(afterSaleOut.getAfterSaleType());
            e.setBizAfterSaleSn(afterSaleOut.getBizAfterSaleSn());
            e.setServerName(afterSaleOut.getServerName());
            e.setShowServerName(afterSaleOut.getShowServerName());
            e.setChannelCode(afterSaleOut.getChannelCode());
            e.setAfterSaleStatus(afterSaleOut.getStatus());
        });
        afterSaleService.modifyAfterSale(modify);

        if (Optional.ofNullable(afterSaleFix.getNotify()).orElse(false)) {
            AfterSaleStateChangeEvent event = new AfterSaleStateChangeEvent();
            event.setAfterSaleSn(modify.getAfterSaleSn());
            event.setAfterSaleType(modify.getAfterSaleType());
            event.setOrderSn(modify.getOrderSn());
            event.setAfterSaleStatus(modify.getStatus());
            event.setOrderAutoCancel(EnumUtils.eq(AfterSaleSourceEnum.SYSTEM, modify.getAfterSaleSource()));
            event.setRefundSuccess(EnumUtils.eq(RefundStatusEnum.REFUND_SUCCESS, modify.getRefundStatus()));
            SpringUtil.publishEvent(event);
        }
        return true;
    }

	@Override
	public Long waitReview() {
		return afterSaleService.waitReview();
	}

	private List<AfterSaleAttributesResult> getSaleAttributesResultList(AfterSaleOutBO afterSaleOut, List<OrderBO> orders, OrderBO order) {
        List<OrderProductBO> orderProductList = order.getOrderProductList();

        List<OrderProductBO> queryOrderProductList = Lists.newArrayList();
        afterSaleOut.getItems().forEach(item -> orderProductList.forEach(orderProduct -> {
            if (Objects.equals(item.getSkuCode(), orderProduct.getSkuCode())) {
                queryOrderProductList.add(orderProduct);
            }
        }));

        CustomAssert.notEmpty(orders, "暂无售后单");
        return afterSaleBoundaryClient.queryAfterSaleReason(order, queryOrderProductList);
    }

    private List<AfterSaleAttributesResult.ReasonDetail> filterAfterSaleTypeReason(Integer afterSaleType,
                                                                                   List<AfterSaleAttributesResult> resultList) {
        List<AfterSaleAttributesResult.ReasonDetail> reasonDetails = Lists.newArrayList();
        for (AfterSaleAttributesResult afterSaleAttribute : resultList) {
            if (CollectionUtils.isEmpty(afterSaleAttribute.getAttributes())) {
                continue;
            }
            for (AfterSaleAttributesResult.Attribute attribute : afterSaleAttribute.getAttributes()) {
                for (AfterSaleAttributesResult.AfterSaleReason afterSaleReason : attribute.getAfterSaleReasons()) {
                    if (EnumUtils.eq(afterSaleReason.getAfterSaleType(), afterSaleType)) {
                        reasonDetails.addAll(afterSaleReason.getReasonDetails());
                    }
                }
            }
        }
        return reasonDetails;
    }
}
